package cc.rengu.igas.channel.xmup.core.packswitch;


import cc.rengu.igas.channel.xmup.common.constant.XmupConfigConstant;
import cc.rengu.igas.channel.xmup.common.constant.XmupParamConstant;
import cc.rengu.igas.channel.xmup.common.constant.XmupTreeNodeConstant;
import cc.rengu.igas.channel.xmup.common.enums.RespCodeEnum;
import cc.rengu.igas.channel.xmup.common.util.XmupSecurityUtil;
import cc.rengu.igas.channel.xmup.facade.base.BaseRequest;
import cc.rengu.jradp.packetswitch.IncomingPackSwitchImpl;
import cc.rengu.jradp.packetswitch.OutgoingPackSwitchImpl;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.BizMsgInfoMapper;
import cc.rengu.oltp.service.common.dao.CertInfoMapper;
import cc.rengu.oltp.service.common.dao.SecPlanInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.BizMsgInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.CertInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.SecPlanInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.*;
import cc.rengu.oltp.service.common.enums.ChannelEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.utility.util.*;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;

import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.List;
import java.util.Optional;

/**
 * 银联全渠道通讯报文解包前后、组前包后实现类
 * Created by 王成 on 2018/12/27.
 */
public class XmupClientPackSwitch implements IncomingPackSwitchImpl, OutgoingPackSwitchImpl {

    @Override
    public byte[] beforeInComPackSwitch(byte[] bytes) throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String recvData = new String(bytes);
        if (!recvData.isEmpty()) {
            /*更新业务报文信息*/
            updateBizMsgInfo(rglog, recvData);
            /* 获取敏感信息加密证书 */
            String secPlanInfoListString = xmlTreeUtil.getXmlTreeStringValue(XmupTreeNodeConstant.SEC_PLAN_INFO_LIST);
            List<SecPlanInfo> secPlanInfoList = JSONArray.parseArray(secPlanInfoListString, SecPlanInfo.class);
            Optional<SecPlanInfo> checkSignSecPlanOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(XmupParamConstant.VERIFY_CERT_TYPE)).findFirst();
            if (checkSignSecPlanOpt.isPresent()) {
                CertInfoMapper certInfoMapper = new CertInfoMapperImpl();
                CertInfo certInfo = certInfoMapper.selectCertInfoByPrimaryKey(checkSignSecPlanOpt.get().getSecPlanId() + checkSignSecPlanOpt.get().getSecPlanType());
                /* 验证签名 */
                if (XmupSecurityUtil.verifySign(recvData, certInfo.getCertValue())) {
                    rglog.info("签名验证成功!");
                    return bytes;
                } else {
                    rglog.error("签名验证失败!");
                    return new byte[0];
                }
            }
        }
        return bytes;
    }

    @Override
    public int afterInComPackSwitch() throws Exception {
        return 0;
    }

    @Override
    public int beforeOutgoPackSwitch() throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        String instId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID);
        SysParamService sysParamService = new SysParamServiceImpl();
        SysParam sysParam = null;
        /* 加载公共信息 */
        sysParam = sysParamService.getSysParamInfo(instId, XmupConfigConstant.XMUP_CONF_NODE, XmupConfigConstant.XMUP_VERSION);
        if (sysParam != null) {
            xmlTreeUtil.setXmlTreeStringValue(XmupTreeNodeConstant.version, sysParam.getParamValue());
        }
        sysParam = sysParamService.getSysParamInfo(instId, XmupConfigConstant.XMUP_CONF_NODE, XmupConfigConstant.XMUP_ENCODING);
        if (sysParam != null) {
            xmlTreeUtil.setXmlTreeStringValue(XmupTreeNodeConstant.encoding, sysParam.getParamValue());
        }
        sysParam = sysParamService.getSysParamInfo(instId, XmupConfigConstant.XMUP_CONF_NODE, XmupConfigConstant.XMUP_SIGN_METHOD);
        if (sysParam != null) {
            xmlTreeUtil.setXmlTreeStringValue(XmupTreeNodeConstant.signMethod, sysParam.getParamValue());
        }
        sysParam = sysParamService.getSysParamInfo(instId, XmupConfigConstant.XMUP_CONF_NODE, XmupConfigConstant.XMUP_BACK_URL);
        if (sysParam != null) {
            xmlTreeUtil.setXmlTreeStringValue(XmupTreeNodeConstant.backUrl, sysParam.getParamValue());
        }
        /* 获取通道配置信息 */
        DstChannelInfo dstChannelInfo = (DstChannelInfo) xmlTreeUtil.getXmlTreeObjectValue(XmupTreeNodeConstant.DST_CHANNEL_INFO, DstChannelInfo.class);
        if (null == dstChannelInfo) {
            rglog.error("获取通道<{}><{}>配置信息失败!", ChannelEnum.XMUP.getChannelType(), ChannelEnum.XMUP.getChannelDesc());
            throw new BizException(RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespCode(), RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespDesc());
        }
        /* 根据通道安全计划获取安全计划 */
        SecPlanInfoMapper secPlanInfoMapper = new SecPlanInfoMapperImpl();
        List<SecPlanInfo> secPlanInfoList = secPlanInfoMapper.selectSecPlanInfoBySecPlanId(instId, dstChannelInfo.getSecPlanId());
        if (null != secPlanInfoList && !secPlanInfoList.isEmpty()) {
            xmlTreeUtil.setXmlTreeStringValue(XmupTreeNodeConstant.SEC_PLAN_INFO_LIST, JSON.toJSONString(secPlanInfoList));
            /* 加签证书 */
            Optional<SecPlanInfo> secPlanInfoOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(XmupParamConstant.SIGN_CERT_TYPE)).findFirst();
            if (secPlanInfoOpt.isPresent()) {
                CertInfoMapper certInfoMapper = new CertInfoMapperImpl();
                CertInfo certInfo = certInfoMapper.selectCertInfoByPrimaryKey(secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
                if (null != certInfo) {
                    if ("2".equals(certInfo.getCertSaveType())) {
                        xmlTreeUtil.setXmlTreeStringValue(XmupTreeNodeConstant.certId, XmupSecurityUtil.getCertIdFromCertFile(certInfo.getCertSavePath(), certInfo.getCertPassword()));
                    } else {
                        xmlTreeUtil.setXmlTreeStringValue(XmupTreeNodeConstant.certId, certInfo.getCertId());
                    }
                }
            }
        }
        xmlTreeUtil.setXmlTreeStringValue("_MESSAGEHEAD/http/Content-Type", "application/x-www-form-urlencoded");
        return 0;
    }

    @Override
    public byte[] afterOutgoPackSwitch(byte[] bytes) throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String msgRegisterFlag = xmlTreeUtil.getXmlTreeStringValue(XmupTreeNodeConstant.MSG_REG_FLAG);
        String content = new String(bytes);
        /*打印原报文内容*/
        rglog.debug("未签名报文：{}", content);
        if (!content.isEmpty()) {
            /* 获取敏感信息加密证书 */
            String secPlanInfoListString = xmlTreeUtil.getXmlTreeStringValue(XmupTreeNodeConstant.SEC_PLAN_INFO_LIST);
            List<SecPlanInfo> secPlanInfoList = JSONArray.parseArray(secPlanInfoListString, SecPlanInfo.class);
            Optional<SecPlanInfo> secPlanInfoOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(XmupParamConstant.SIGN_CERT_TYPE)).findFirst();
            if (secPlanInfoOpt.isPresent()) {
                CertInfoMapper certInfoMapper = new CertInfoMapperImpl();
                CertInfo certInfo = certInfoMapper.selectCertInfoByPrimaryKey(secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
                /* 加签 */
                String signData = null;
                if ("0".equals(certInfo.getCertSaveType())) {
                    signData = XmupSecurityUtil.sign(content, certInfo.getCertValue());
                } else if ("2".equals(certInfo.getCertSaveType())) {
                    List<String> aliasList = RSAUtil.getCertAliasFromPfxCertFile(certInfo.getCertSavePath(), certInfo.getCertPassword());
                    PrivateKey privateKey = RSAUtil.getPrivateKeyFromPfxCertFile(certInfo.getCertSavePath(), aliasList.get(0), certInfo.getCertPassword());
                    PublicKey publicKey = RSAUtil.getPublicKeyFromPfxCertFile(certInfo.getCertSavePath(), aliasList.get(0), certInfo.getCertPassword());
                    signData = XmupSecurityUtil.sign(content, privateKey, publicKey);
                } else {
                    rglog.error("暂时不支持证书存储方式<{}>", certInfo.getCertSaveType());
                    throw new BizException(RespCodeEnum.CERT_SAVE_TYPE_ERROR.getRespCode(), RespCodeEnum.CERT_SAVE_TYPE_ERROR.getRespDesc());
                }
                /*登记业务报文表*/
                if (AppParamConstant.YES.equals(msgRegisterFlag)) {
                    registerBizMsgInfo(rglog, signData);
                }
                return signData.getBytes();
            }
        }
        return bytes;
    }

    private void registerBizMsgInfo(RgLogger rglog, String bizMsg) {
        try {
            XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
            if (bizMsg.length() > 8000) {
                rglog.error("存储转发报文超过8K，暂不登记到存储转发表:<{}>", bizMsg);
                return;
            }
            BizMsgInfo bizMsgInfo = new BizMsgInfo();
            BizMsgInfoMapper bizMsgInfoMapper = new BizMsgInfoMapperImpl();
            BaseRequest baseRequest = new BaseRequest();
            ConvertUtil.convertOutput(baseRequest);
            bizMsgInfo.setInstId(baseRequest.getHeader().getInstId());
            bizMsgInfo.setChannelId(ChannelEnum.XMUP.getChannelType());
            bizMsgInfo.setTransSeqNum(baseRequest.getHeader().getTraceNo());
            bizMsgInfo.setTxnDate(baseRequest.getHeader().getTransDate());
            bizMsgInfo.setTxnTime(baseRequest.getHeader().getTransTime());
            bizMsgInfo.setDstTxnNum(baseRequest.getHeader().getTxnNum());
            bizMsgInfo.setCreateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
            if (bizMsg.length() < 4000) {
                bizMsgInfo.setBizReqMsg(bizMsg);
            } else {
                bizMsgInfo.setBizReqMsg(bizMsg.substring(0, 4000));
                bizMsgInfo.setBizReqExpandMsg(bizMsg.substring(4000));
            }
            int iReturnCode = bizMsgInfoMapper.insertBizMsgInfo(bizMsgInfo);
            if (0 != iReturnCode) {
                return;
            }
            xmlTreeUtil.setXmlTreeObjectValue(XmupTreeNodeConstant.BIZ_MSG_INFO, bizMsgInfo);
        } catch (Exception e) {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            e.printStackTrace(new PrintWriter(byteArrayOutputStream, true));
            rglog.error("登记业务报文信息表异常:<{}>", byteArrayOutputStream.toString());
        }
    }

    private void updateBizMsgInfo(RgLogger rglog, String bizRspMsg) {
        try {
            XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
            if (bizRspMsg.length() > 8000) {
                rglog.error("存储转发报文超过8K，暂不登记到存储转发表:<{}>", bizRspMsg);
                return;
            }
            if (xmlTreeUtil.isExist(XmupTreeNodeConstant.BIZ_MSG_INFO)) {
                rglog.error("获取请求业务报文节点失败，不更新");
                return;
            }
            BizMsgInfo bizMsgInfo = (BizMsgInfo) xmlTreeUtil.getXmlTreeObjectValue(XmupTreeNodeConstant.BIZ_MSG_INFO, BizMsgInfo.class);
            BizMsgInfoMapper bizMsgInfoMapper = new BizMsgInfoMapperImpl();
            bizMsgInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
            if (bizRspMsg.length() < 4000) {
                bizMsgInfo.setBizRspMsg(bizRspMsg);
            } else {
                bizMsgInfo.setBizRspMsg(bizRspMsg.substring(0, 4000));
                bizMsgInfo.setBizRspExpandMsg(bizRspMsg.substring(4000));
            }
            int iReturnCode = bizMsgInfoMapper.updateBizMsgInfoByTransSeqNum(bizMsgInfo);
            if (0 != iReturnCode) {
                return;
            }
        } catch (Exception e) {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            e.printStackTrace(new PrintWriter(byteArrayOutputStream, true));
            rglog.error("登记业务报文信息表异常:<{}>", byteArrayOutputStream.toString());
        }
    }
}
